import random
import string

from flask import Blueprint, render_template, jsonify, redirect, url_for, session
from flask_mail import Message

from exts import mail, db
from flask import request
from models import EmailCaptchaModel
from blueprints.forms import RegisterForm, LoginFrom
from models import UserModel
from werkzeug.security import generate_password_hash, check_password_hash

# bp 是你在 Python 代码中给这个蓝图对象起的 变量名,它的作用是：在当前文件中方便地添加路由、配置蓝图
bp = Blueprint("auth", __name__, url_prefix="/auth")


@bp.route("/login", methods=["GET", "POST"])
def login():
    # 1、从服务器端获取渲染的注册页
    if request.method == "GET":
        return render_template("login.html")
    else:
        # 2、把填写的用户信息，提交给服务器
        # 3、把前端输入的form信息传递给LoginForm验证表单类，并生成实例对象
        form = LoginFrom(request.form)
        # 4、调用类的validate（）验证方法，会自动执行LoginForm类里的所有验证方法
        if form.validate():
            # 5、取得表单页面填入的数据
            email = form.email.data
            password = form.password.data
            # 6、查找数据库表中是否存在填入的邮箱
            user = UserModel.query.filter_by(email=email).first()
            if not user:
                print("邮箱在数据库中不存在")
                return redirect(url_for("auth.login"))
            # user.password哈希字符串，password明文密码，做对比
            if check_password_hash(user.password, password):
                # cookie:一般用来存放登录授权的东西，只适合存放少量数据
                # flask中的session，是经过加密后存储到cookie中的，session存储值类似于字典
                # 这一步session会自动把加密后的user_id传递给cookie，然后cookie存放在浏览器中；下次用户在登录时，浏览器会自动把cookie中的uer_id发送给服务器的flask解析，通过验证user_id匹配后，从而登录成功
                session['user_id'] = user.id
                return redirect("/")
            else:
                print("密码错误！")
                return redirect(url_for("auth.login"))
        else:
            print(form.errors)
            return redirect(url_for("auth.login"))


# GET：从服务器获取数据 （从服务器端获取渲染的注册页面）
# POST：将客户端数据发送给服务器 （把填写的用户信息，提交给服务器）
@bp.route("/register", methods=["GET", "POST"])
def register():
    # 1、从服务器端获取渲染的注册页
    if request.method == "GET":
        return render_template("register.html")
    else:
        # 验证用户提交的邮箱和验证码是否对应且正确；表单验证：flask-wtf:wtforms,pip install flask-wtf
        # 2、把填写的用户信息，提交给服务器
        # 2.1、把前端输入的form信息传递给RegisterForm表单类，并生成实例对象
        form = RegisterForm(request.form)
        # 2.2、调用类的validate（）验证方法，会自动执行RegisterForm类里的所有验证方法
        if form.validate():
            # 2.3、获得表单中的信息，并生成用户模型的实例对象
            email = form.email.data
            username = form.username.data
            password = form.password.data
            # 注意：密码不能跟邮箱一样直接赋值明文密码，必须要flask的generate_password_hash()加密处理
            user = UserModel(email=email, username=username, password=generate_password_hash(password))

            # 2.4、把用户模型的实例对象提交给数据库
            db.session.add(user)
            db.session.commit()
            # 2.5、注册成功后跳转到登录页面
            # redirect（）里有两种跳转url的写法：1、直接写全路径：/auth/login; 2、把路径写在url_for("auth.login"),推荐这种
            # return redirect("/auth/login")
            return redirect(url_for("auth.login"))
        else:
            # 3、否则输出失败原因，并重新返回注册页面
            print(form.errors)
            return redirect(url_for("auth.register"))


# 退出登录,返回首页
@bp.route("logout")
def logout():
    session.clear()
    return redirect("/")


# @bp.route()默认提交方式是get提交，method也可以改成post;GET：从服务器获取数据，POST：提交数据给服务器
@bp.route("/captcha/email", methods=["GET"])
def get_email_captcha():
    # 在浏览器中有两种传参方式：/captcha/email/<email> 和 /captcha/email?email=xxx@qq.com
    email = request.args.get("email")
    # 4/6位验证码，随机数组，字母或数组，字母的组合
    source = string.digits * 4
    captcha = random.sample(source, 4)
    captcha = "".join(captcha)
    # I/O：Input/Output。正式项目中都会把耗时较长的io操作放到队列任务中做，如Celery +redis实现异步任务队列，就是交给另一个线程去做；
    # 而视图函数只生成验证码，把参数传递给另一个进程，去发送邮件；从而不影响验证码计数器计数，至于发送邮件耗时另一个操作
    message = Message(subject="邮箱验证码发送测试", recipients=[email], body=f"验证码：{captcha}")
    mail.send(message)

    # memcached：存储到内存中，缺点一旦遇到断电等情况，数据就没有了
    # redis：存储到硬盘中，也有同步机制 （所有大型网站必备！）
    # 用数据库表的方式存储：速度较慢，适用于小型网站
    email_captcha = EmailCaptchaModel(email=email, captcha=captcha)
    db.session.add(email_captcha)
    db.session.commit()
    # RESTful API,前后端数据格式必须一致
    # {"code": 200 / 400 / 500, "message": "", "data": "None"}
    return jsonify({"code": 200, "message": "", "data": "None"})


@bp.route("/mail/test")
def mail_test():
    message = Message(subject="邮箱验证码发送测试", recipients=["xxx@qq.com"], body="这是一条测试邮件121")
    mail.send(message)
    return "邮件发送成功！"
